using System;

using NUnit.Framework;

using WCSFContrib.Extensions.CompositeWeb;
using WCSFContrib.Extensions.EventBroker;
using WCSFContrib.Extensions.Utility;

namespace WCSFContrib.Extensions.Tests.CompositeWeb
{
	[TestFixture]
	public class MediatorTests
	{
		[Test]
		public void MediatorHookupStringFromAToB()
		{
			string expectedResult = "42";

			// Setup
			Mediator<IA, IB> mediator = new Mediator<IA, IB>();
			A a = new A();
			B b = new B();
			mediator.SModel = a;
			mediator.TModel = b;

			// Pre
			Assert.AreEqual(0, b.WhenFooHappensCount);

			// Test
			a.OnFoo(expectedResult);
			string result = b.WhenFooHappensData;

			// Post
			Assert.AreEqual(1, b.WhenFooHappensCount);
			Assert.AreEqual(expectedResult, result);
		}

		[Test]
		public void MediatorHookupEventFromBToA()
		{
			EventArgs e = EventArgs.Empty;

			// Setup
			Mediator<IA, IB> mediator = new Mediator<IA, IB>();
			A a = new A();
			B b = new B();
			mediator.SModel = a;
			mediator.TModel = b;

			// Pre
			Assert.AreEqual(0, a.WhenBarHappensCount);

			// Test
			b.OnBar(e);

			// Post
			Assert.AreEqual(1, a.WhenBarHappensCount);
			Assert.AreSame(b, a.WhenBarHappensO);
			Assert.AreSame(e, a.WhenBarHappensE);
		}

		[Test]
		public void HandlerOnBListensToTwoEvents()
		{
			// Setup
			Mediator<IA, IB> mediator = new Mediator<IA, IB>();
			A a = new A();
			B b = new B();
			mediator.SModel = a;
			mediator.TModel = b;

			// Pre
			Assert.AreEqual(0, b.WhenAnythingHappensCount);

			// Test
			a.OnFoo(null);

			// Post
			Assert.AreEqual(1, b.WhenAnythingHappensCount);

			// Test
			a.OnBas(EventArgs.Empty);

			// Post
			Assert.AreEqual(2, b.WhenAnythingHappensCount);
		}

		private struct Topics
		{
			public const string FirstEvent = "foo";
			public const string SecondEvent = "bar";
			public const string ThirdEvent = "bas";
		}

		private interface IA
		{
			[EventPublication(Topics.FirstEvent)]
			event EventHandler<DataEventArgs<string>> FooEvent;

			[EventPublication(Topics.ThirdEvent)]
			event EventHandler BasEvent;

			[EventSubscription(Topics.SecondEvent)]
			void WhenBarHappens(object sender, EventArgs e);
		}

		private interface IB
		{
			[EventSubscription(Topics.FirstEvent)]
			void WhenFooHappens(string data);

			[EventPublication(Topics.SecondEvent)]
			event EventHandler BarEvent;

			[EventSubscription(Topics.FirstEvent)]
			[EventSubscription(Topics.ThirdEvent)]
			void WhenAnythingHappens();
		}

		private class A : IA
		{
			public event EventHandler<DataEventArgs<string>> FooEvent;
			public event EventHandler BasEvent;

			public int WhenBarHappensCount = 0;
			public object WhenBarHappensO;
			public EventArgs WhenBarHappensE;

			public void OnFoo(string foo)
			{
				FooEvent.Invoke(this, new DataEventArgs<string>(foo));
			}

			public void OnBas(EventArgs e)
			{
				BasEvent.Invoke(this, e);
			}

			public void WhenBarHappens(object sender, EventArgs e)
			{
				WhenBarHappensCount++;
				WhenBarHappensO = sender;
				WhenBarHappensE = e;
			}
		}

		private class B : IB
		{
			public event EventHandler BarEvent;

			public string WhenFooHappensData;
			public int WhenFooHappensCount = 0;

			public int WhenAnythingHappensCount = 0;

			public void WhenFooHappens(string data)
			{
				WhenFooHappensCount++;
				WhenFooHappensData = data;
			}

			public void OnBar(EventArgs e)
			{
				BarEvent.Invoke(this, e);
			}

			public void WhenAnythingHappens()
			{
				WhenAnythingHappensCount++;
			}
		}
	}
}